
/**
	*	@file upload.c
	*	@brief Programa responsável pelo carregamento inicial do arquivode dados e do arquivo de indice.
	*   @author  Daniel Bittencourt e Davi Viana
	*   @version 14
	*
	*   Este programa incializa o arquivo de dados no disco, faz a leitura da base de dados e insere estas
	*	informaçõe no arquivo de dados. Também faz a incialização do arquivo
	*
	*	@sa BD1.h
	*
	**/



#include "BD1.h"

/**
	*	@brief contColisao é um contador global que indica quantas colisões ocorreram no inserção dos registros no hash.
	*	@var contColisao Vetor de Caracteres que possui os dias da semana
	**/
int contColisao=0;
/*
void calculaBLK() {

	FILE *blk_info;
	system("/sbin/debugreiserfs /dev/sda3 | awk '/^Blocksize/{print $2}' >> /tmp/blk_sz" );
	blk_info = fopen("/tmp/blk_sz","r");
	fscanf(blk_info,"%d",&blk_size);
	fclose(blk_info);
	printf("Block Size: %d\n",blk_size);
	reg_blk = blk_size / 102;
	printf("Reg Por Bloco: %d\n",reg_blk);
}*/

/**
*   @fn tipoDado alocaDados()
*   @brief Esta funcao aloca espacos de memória para onde irão as informações lidas
*   de cada linha do arquivo base para depois serem enseridas no arquivo de dados.
*   Adotamos este método pois a definição estática de um tipo já contendo todas os vetores de caracteres
*   alocados (char CODIOGO[8], por exemplo) estava causando problemas que resultavam em um stack smashing
*   @return Retorna o tipoDado temp com seus capos devidamente alocados
*/

tipoDado alocaDados(){
    tipoDado temp;

    temp.CODIGO = (char *) malloc (sizeof(char) * 8);
    temp.NOME = (char *) malloc (sizeof(char) * 60);
    temp.DATA_NASC = (char *) malloc (sizeof(char) * 10);
    temp.LOCAL = (char *) malloc (sizeof(char) * 32);

    return temp;
}


/**
*   @fn int funcHash1(int CODIGO)
*   @brief Função de hash que retorna o valor aonde deverá ser gravado o dado.
*   @param CODIGO Codigo lido da linha do arquivo base já convertida para inteiro
*   @return retorna o bucket que receberá o registro
*/

int funcHash1(int CODIGO){
    return (CODIGO % num_buckets);
}

/*
*Função de hash para quando o indice de utilização for maior que 80%
*Funcao não utilizada pois o hash não precisou ter operaçoes de controle de colisao
*/

int funcHash2(int CODIGO){
    return (CODIGO % 2*num_buckets);
}

/**
*   @fn tipoDado leTupla(char* linha, tipoDado *registro)
*   @brief Funcao que le os dados da linha do arquivo que contém a base e separa os campos
*   devolvendo um registro com os campos já separados para poder serem inseridos no arquivo hash
*   @param linha Linha lida do arquivo com a base de dados
*   @param registro Ponreito para o registro temporário que recebera as informações da linha lida da base de dados
*   @return retorna o registro com os campos preenchidos pelas informações da linha lida
*/

tipoDado leTupla(char* linha, tipoDado* registro){
    tipoDado reg;

    strcpy(registro->CODIGO, strtok(linha, "\t"));
    strcpy(registro->NOME, strtok(NULL, "\t"));
    strcpy(registro->DATA_NASC, strtok(NULL, "\t"));
    strcpy(registro->LOCAL, strtok(NULL, "\n"));
}

/**
*   @fn void iniciaArqDados(FILE *arqDados)
*   @brief Fucao que cria o arquivo de dados em disco.
*   Fucao que cria o arquivo de dados em discoinicializando as infomacoes complementares
*   de daca bucket (blkAtual e fatorUtil) e alocando todos os buckets nescessários para guardar os dados
*   no arquivo
*   @param arqDados Ponterio para o arquivo de dados aberto.
*   @return A fuc. não retorna nada
*/

void iniciaArqDados(FILE* arqDados){
	int i;
	tipoBucket bucket;

    //Define que cada bloco começara as inserções no bloco 0 do bucket
    //tera fazor de utilizcao inicial igual a zero
    bucket.blkAtual = 0;
    bucket.fatorUtil = 0;
    for(i=0;i<37;i++){
        bucket.blocos[i].regAtual = 0;
    }


	//Cria o arquivo binario de dados para gravacao.
	if (( arqDados = fopen("arqDados.bin", "wb") ) == NULL ){
		printf( "\nErro na criacao do arquivo\n");
		exit(1);
	}

	//Aloca no Disco a quantidade inicial de buckets num_buckets = 552
	for(i=0; i<num_buckets;i++){
		//Cria o bucket no disco
		if (fwrite(&bucket, sizeof(tipoBucket), 1, arqDados) != 1)
			printf("\nErro na escrita inicial do arquivo de dados\n");
	}

	//Fecha o arquivo de dados de registros
	fclose(arqDados);
}

/**
*   @fn carregaDados(FILE *arqDados, tipoDado *registro, int posbucket)
*   @brief Fucao que insere os dados lidos no arquivo de dados pré criado pela funcao inciaArqDados.
*
*   Para ele são passados o ponteiro do arquivo de dados, o ponteiro do arquivo de indices o registro e o bucket
*   calculado pela funcao hash. Entao ele multiplica o numero do bucket passado como parâmetro pelo tamanho de um bucket. Este será
*   o offset dado a partir do inicio do arquivo até a posicao corresponente do bucket que recebera o registro.
*   entao um bucket é lido do arquivo de dados para uma variável temporária a qual recebe na posicao indicada por blkAtual (presente em bucket)
*   e na posicao indicada por regAtual (presente em cada elemento do vetor de blocos do TidoBloco) o reg. que receberá os dados lidos do arq. de dados.
*   A cada insercao o contador regAtual é incrementado dento do bloco atual. Quando este chega a 37 significa que o bloco esta cheio e entao passamos para o próximo
*   bloco  (tempBucket.blkAtual += 1). Se blkAtual é igual a 98. Quer dizer que o Bucket de destino está cheio e portanto temos uma colisao.
*   Mas supondo que não houve colisão, os dados do registro passado como parâmetro para a funcao são escritos no registro, do bloco atual, do bucket lido do disco
*   e depois reescritos no arquivo de dados. Completado a inserção dos dados.
*
*   @param arqDados Ponterio para o arquivo de dados aberto
*   @param registro Ponterio para o uma variável do tipo registro com as informações a serem escritas no arquivos de dados
*   @param posbucket Número do bucket no arquivo de dados
*   @return A fucao ao retorna nada
*/

void carregaDados(FILE* arqDados, tipoDado* registro, int posbucket){
    int temp = 1;
    tipoBucket tempBucket;

    fseek(arqDados, posbucket * sizeof(tipoBucket), SEEK_SET);
    fread(&tempBucket, sizeof(tipoBucket), 1, arqDados);
    if(tempBucket.blkAtual < 98){
        if (tempBucket.blocos[tempBucket.blkAtual].regAtual == 37){
            tempBucket.blkAtual += 1;
        }

        strcpy (tempBucket.blocos[tempBucket.blkAtual].registros[tempBucket.blocos[tempBucket.blkAtual].regAtual].CODIGO, registro->CODIGO);
        strcpy (tempBucket.blocos[tempBucket.blkAtual].registros[tempBucket.blocos[tempBucket.blkAtual].regAtual].NOME, registro->NOME);
        strcpy (tempBucket.blocos[tempBucket.blkAtual].registros[tempBucket.blocos[tempBucket.blkAtual].regAtual].DATA_NASC, registro->DATA_NASC);
        strcpy (tempBucket.blocos[tempBucket.blkAtual].registros[tempBucket.blocos[tempBucket.blkAtual].regAtual].LOCAL, registro->LOCAL);
        tempBucket.blocos[tempBucket.blkAtual].regAtual += 1;
    }
    else
    //printf("Bucket Cheio não foi possivel inserir\n");
    contColisao++;

    fseek(arqDados, posbucket * sizeof(tipoBucket), SEEK_SET);
    fwrite(&tempBucket,1,sizeof(tipoBucket),arqDados);


}

/**
*   @fn verificaFolha(tipoNoAvore no)
*   @brief Faz a verificação se o nó é uma folha da arvore binaria.
*   @param no nó onde se vai fazer a verificação.
*   @return Se o nó é folha ou não.
*/

int verificaFolha (tipoNoArvore no){
        return (no.filhos[0] == -1);
    }

/**
*   @fn verificaOverflow(tipoNoAvore no)
*   @brief Faz a verificação se a capacidade de armazenamento de chaves do nó está no limite.
*   @param no nó onde se vai fazer a verificação.
*   @return Se ouve overflow no nó ou não.
*/

int verificaOverflow (tipoNoArvore no){
        return(no.numChaves==maxChaves+1);
    }

/**
*   @fn inicializaNo(tipoNoAvore *no)
*   @brief Inicaliza o nó com todos os valores zerados.
*   @param no nó que irá inicializar.
*   @return não retorna nada.
*/
void inicializaNo(tipoNoArvore *no){
	int i;
	(*no).numChaves=0;
	for(i=0;i<maxChaves;i++){
		strcpy((*no).chaves[i].nome,"");
		(*no).chaves[i].pontArqDados=-1;
		(*no).filhos[i]=-1;
	}
	(*no).filhos[maxChaves+1]=-1;

}

/**
*   @fn criaRaiz(tipoNoArvore raiz, char chave[60], long pontArqDados,long filhoEsq, long filhoDir)
*   @brief Cria a raiz da arvore B e atribui a ela um único valor de chave.
*   @param raiz onde irá se criar a raiz.
*   @param chave[60] campo que conterá a chave que será incluída no nó raiz.
*   @param pontArqDados ponteiro para o Arquivo de Dados.
*   @param filhosEsq ponteiro para o local no arquivo onde está armazenado o filho a esquerda do nó raiz.
*   @param filhosDir ponteiro para o local no arquivo onde está armazenado o filho a esquerda do nó raiz.
*   @return a raiz criada.
*/
tipoNoArvore criaRaiz(tipoNoArvore raiz, char chave[60], long pontArqDados,long filhoEsq, long filhoDir){
	inicializaNo(&raiz);
	strcpy(raiz.chaves[0].nome,chave);
	raiz.chaves[0].pontArqDados=pontArqDados;
    	raiz.filhos[0]=filhoEsq;
	raiz.filhos[1]=filhoDir;;
	raiz.numChaves=1;

	return raiz;
}

/**
*   @fn splitNo (FILE *arqIndices, tipoNoArvore no, int ord)
*   @brief Quando ocorre overflow no nó é chamada esta função para dividir o nó.
*   @param arqIndices ponteiro para o arquivo de indices pois o mesmo também será modificado.
*   @param no nó onde ocorrerá o split.
*   @param ord informa o local onde ocorrerá o split dentro do vetor de chaves
*   @param filhosEsq ponteiro para o local no arquivo onde está armazenado o filho a esquerda do nó raiz.
*   @param filhosDir ponteiro para o local no arquivo onde está armazenado o filho a esquerda do nó raiz.
*   @return Quando o split ocorre com sucesso retorna 1.
*/

int splitNo (FILE *arqIndices, tipoNoArvore no, int ord)
{
	int i,j;
	tipoNoArvore auxNo;
	long pos;

	inicializaNo(&auxNo);

	i=ord+1;  // local onde ocorrerá o split

	for(j=0;i!=no.numChaves;j++){
		strcpy(auxNo.chaves[j].nome,no.chaves[i].nome);
		auxNo.chaves[j].pontArqDados=no.chaves[i].pontArqDados;
		auxNo.filhos[j]=no.filhos[i];
		strcpy(no.chaves[i].nome,"");
		no.chaves[i].pontArqDados=-1;
		i++;

	}
	auxNo.filhos[j+1]=no.filhos[i];	
	auxNo.numChaves=metadeBloco+1;
	no.numChaves=metadeBloco+1;

	
	fseek(arqIndices,0,SEEK_END); 	//Posiciona no fim do arq
	pos=ftell(arqIndices);
	auxNo.offset=pos;
	//Grava em disco
	if(fwrite(&auxNo,sizeof(tipoNoArvore),1,arqIndices)!=1)
		printf("Erro na escrita do arquivo de indices.\n");
    return 1;
	//fclose(arqIndices);

}

/**
*   @fn inserirChaveNo (FILE *arqIndices, tipoNoArvore no, int i, char chave[60], long pontArqDados, long apontBloco, long apontPai)
*   @brief Faz a primeira parte da inserção de uma nova chave, onde é verificada se vai ocorrer overflow ou não.
*   @param arqIndices ponteiro para o arquivo de indices pois o mesmo também será modificado.
*   @param no nó onde irá se inserir a chave.
*   @param i informa o local onde ocorrerá ocorrer a inserção dentro do vetor de chaves
*   @param pontArqDados ponteiro para o local no arquivo de dados onde está os dados do nó.
*   @param apontBloco ponteiro para onde está o bloco no arquivo de indices.
*   @param apontPai ponteiro que indicará onde está o pai do nó que se está trabalhando dentro do arquivo de indices.
*   @return Quando a inserção da chave foi realizada com suceso, retorna 1.
*/

int inserirChaveNo (FILE *arqIndices, tipoNoArvore no, int i, char chave[60], long pontArqDados, long apontBloco, long apontPai){
	tipoNoArvore raiz, auxPai;
	long apontDir,apontEsq, auxPontArqDados, posicao, finalArqIndices, auxApontBloco;
	int j;
	char auxNome[60];
	
	inicializaNo(&raiz); // faz a inicialização do no raiz

	finalArqIndices=no.offset;
	auxApontBloco=apontBloco;

	// faz a verificação caso a posição já esteja sendo usada
	if(no.numChaves > i)
	{
		no.filhos[no.numChaves+1]=no.filhos[no.numChaves];
		for(j=(no.numChaves-1);j>=i;j--)
		{
			strcpy(no.chaves[j+1].nome,no.chaves[j].nome);
			no.chaves[j+1].pontArqDados=no.chaves[j].pontArqDados;
		}
	}

	strcpy(no.chaves[i].nome,chave);
	no.chaves[i].pontArqDados=pontArqDados;
	no.numChaves++;
	no.filhos[i+1]=auxApontBloco;
	no.offset=finalArqIndices;

	if(verificaOverflow(no))  // faz a verificação se ocorreu overflow
	{
		strcpy(auxNome,no.chaves[metadeBloco].nome);
		auxPontArqDados=no.chaves[metadeBloco].pontArqDados;
		posicao=no.offset;
		apontDir=splitNo(arqIndices, no,metadeBloco);
		no.filhos[metadeBloco]=apontBloco;
		strcpy(no.chaves[metadeBloco].nome,"");
		no.chaves[metadeBloco].pontArqDados=-1;
		no.numChaves=metadeBloco;

		if(apontPai==-2)
		{
			fseek(arqIndices,0,SEEK_END);
			apontEsq=ftell(arqIndices);
			no.offset=apontEsq;

			if(fwrite(&no,sizeof(tipoNoArvore),1,arqIndices)!=1)
				printf("Erro no arquivo indices\n");
			raiz = criaRaiz(raiz,auxNome,auxPontArqDados,apontEsq,apontDir);
			raiz.offset=posicao;
			fseek(arqIndices,posicao,SEEK_SET);
			if(fwrite(&raiz,sizeof(tipoNoArvore),1,arqIndices)!=1)
				printf("Erro no arquivo de indices.\n");
		}
		else
		{
			fseek(arqIndices,no.offset,SEEK_SET);
			if(fwrite(&no,sizeof(tipoNoArvore),1,arqIndices)!=1)
				printf("Erro no arquivo índices.\n");

			inicializaNo(&auxPai); // inicializa o nó que irá auxiliar o nó pai.
			fseek(arqIndices,apontPai,SEEK_SET);

			if(fread(&(auxPai),sizeof(tipoNoArvore),1,arqIndices)!=1){
		        	printf("Erro no arquivo de indices.\n");
				return 0;
			}

			for(j=0; ((j<auxPai.numChaves) && (chave > (auxPai).chaves[j].nome));j++); //Localiza o local da inserção

			if(auxPai.offset==0)
				inserirChaveNo(arqIndices, auxPai, j, chave, auxPontArqDados, apontDir, -2);
		}
	}
	else{
		fseek(arqIndices,no.offset,SEEK_SET);
		if(fwrite(&no,sizeof(tipoNoArvore),1,arqIndices)!=1)
			printf("Erro no arquivo de indices./n");
	}


	return 1;
}

/**
*   @fn procurarPosicaoInserir (FILE *arqIndices, tipoNoArvore *no, char chave[60], long pontArqDados ,long offset, long apontPai)
*   @brief Para não ficar todo o código em uma função só, foi definido está segunda função que irá auxiliar na inserção da chave do nó,
*   esta função irá procurar o local exato no vetor de chaves onde irá se fazer a inserção.
*   @param arqIndices ponteiro para o arquivo de indices pois o mesmo também será modificado.
*   @param no nó que será lido do arquivo de indices que terá a nova chave.
*   @param chave irá conter a chave que será inserida no vetor de chaves do nó.
*   @param pontArqDados ponteiro para o local no arquivo de dados onde está os dados do nó.
*   @param offset local onde se encontra o nó que será lido no arquivo de indices.
*   @param apontPai ponteiro que indicará onde está o pai do nó que se está trabalhando dentro do arquivo de indices.
*   @return Quando tudo ocorrer corretamente a função irá retornar 1.
*/

int procurarPosicaoInserir (FILE *arqIndices, tipoNoArvore *no, char chave[60], long pontArqDados ,long offset, long apontPai)
{
	tipoNoArvore auxBloco;
	int i = 0;

	inicializaNo(&auxBloco); // irá auxiliar no caso de o nó não ser folha.
	fseek(arqIndices,offset,SEEK_SET);

	if (fread(&(*no), sizeof(tipoNoArvore), 1, arqIndices) != 1)
		printf("\nErro no arquivo de indices: \n" );

	while ((i<(*no).numChaves) && (chave > (*no).chaves[i].nome)) i++;  // Faz a varredura para verificar onde vai ser inserido.
	if (verificaFolha((*no))) // verifica se é folha, se for basta inserir na posicao i
	{
		inserirChaveNo (arqIndices, (*no), i, chave, pontArqDados, -1, apontPai);
	}
	else	inserirChaveNo (arqIndices, auxBloco, i, chave, pontArqDados, (*no).filhos[i], offset);
	return 1;
}

/**
*   @fn inserirNaArvore(FILE *arqIndices, char chave[60], long pontArqDados, tipoNoArvore *bloco)
*   @brief É a função principal da inserção na arvore, que faz a inserção da chave caso o nó seja vazio (numChaves = 0), ou chama a função procurarPosicaoInserir para inserir a chave.
*   @param arqIndices ponteiro para o arquivo de indices pois o mesmo será lido e modificado.
*   @param chave[60] chave que irá ser inserida.
*   @param pontArqDados ponteiro para o local no arquivo de dados onde está os dados do nó.
*   @param apontBloco ponteiro para onde está o bloco no arquivo de indices.
*   @param apontPai ponteiro que indicará onde está o pai do nó que se está trabalhando dentro do arquivo de indices.
*   @return Quando a inserção da chave foi realizada com suceso, retorna 1.
*/

long inserirNaArvore(FILE *arqIndices, char chave[60], long pontArqDados, tipoNoArvore *bloco){

	tipoNoArvore blocoLido, auxBloco;
	int i;

	inicializaNo(&auxBloco); // irá auxiliar no processo de inserção na arvore.
	fseek(arqIndices,0,SEEK_SET);

	if (fread(&blocoLido, sizeof(tipoNoArvore), 1, arqIndices) != 1)
		printf("\nErro no arquivo de indices: \n");

	auxBloco.numChaves = blocoLido.numChaves;
	for(i=0;i<blocoLido.numChaves;i++)
	{
		strcpy(auxBloco.chaves[i].nome,blocoLido.chaves[i].nome);
		auxBloco.chaves[i].pontArqDados = blocoLido.chaves[i].pontArqDados;
		auxBloco.filhos[i] = blocoLido.filhos[i];
	}
	auxBloco.filhos[i+1] = blocoLido.filhos[i+1];

	if(blocoLido.numChaves==0)
	{
		strcpy(blocoLido.chaves[0].nome, chave);
		blocoLido.chaves[0].pontArqDados = pontArqDados;
		blocoLido.numChaves = 1;
		fseek(arqIndices,0,SEEK_SET);
		blocoLido.offset = ftell(arqIndices);

		if (fwrite(&blocoLido, sizeof(tipoNoArvore), 1, arqIndices) != 1)
			printf("\nErro no arquivo de indices: \n");

	}
	else
	{
		//Chama a funcao auxiliar para insercao recursiva no noh
		if(!procurarPosicaoInserir(arqIndices, &auxBloco,chave,pontArqDados,blocoLido.offset, -2))
			return 0;
	}

	fclose(arqIndices);
	return 1;
}


/**
*   @fn int main(int argc,char **argv)
*   @brief Main do programa. Chama a criacão do arquivo de dados inicial. Abre o aquivo base passado como argumento para o prog.
*   chama a função que faz a leitura dos registros do arquivo base, calcula o bucket pela funcao hash com base no código lido e chama
*   chama a funcao de inserção do arquivo de dados.
*   @param argc Conta a quantidade de parâmetros passados para o programa.
*   @param argv Recebe as strings das informações passadas como parâmetro para o programa
*   @sa @fn iniciaArqDados(FILE *arqDados)
*   @sa @fn tipoDado alocaDados()
*   @sa @fn tipoDado leTupla(char* linha, tipoDado *registro)
*   @sa @fn int funcHash1(int CODIGO)
*   @sa @fn void carregaDados(FILE *arqDados, tipoDado *registro, int posbucket)
*/

int main(int argc,char **argv){

    tipoDado regTemp;
	tipoBucket buk;
	//TBlocoIndice bi;
	char *linha,lixo;
	int resultHash,codigo,cont=0;
	FILE *arqTxt;
    FILE *arqDados;
    FILE *arqIndices;

    //printf("The page size for this system is %ld bytes\n", sysconf(_SC_PAGE_SIZE)); //_SC_PAGE_SIZE is OK too.


    //Verifica se o arquivo TXT eh passado como parametro
	if( argc < 2 ){
		printf("\nModo de usar:\n     %s [arq_de_entrada]\n\n", argv[0] );
		return 1;
	}


	//Abre arquivo TXT para leitura
	if ((arqTxt = fopen(argv[1],"r")) == NULL){
		printf("\nErro na abertura do arquivo de entrada\n");
		return 1;
	}

	//Cria o arquivo de dados
	iniciaArqDados(arqDados);

	//Cria Arquivo de Indice Primario
	//arqIndicePrimarioInit(bi, arqIndices);

	//Aloca espaço para a leitura de uma linha
    linha = (char *) malloc(sizeof(char)*110);

    //abre arquivo binario de dados para leitura e escrita
    if (( arqDados = fopen("arqDados.bin", "r+b") ) == NULL ){
			printf( "\nErro na abertura do arquivo base\n");
			return 1;
    }

    //abre arquivo binario de indices para leitura e escrita
    /*if (( arqIndices = fopen("arqIndicePrimario.bin", "r+b") ) == NULL ){
			printf( "\nErro na abertura do arquivo de indices\n");
			exit(1);
    }*/

	//Enquanto o arquivo nao chegou ao fim, le as tuplas e carrega no arquivo de dados
	while (!feof(arqTxt) ){

        fgets(linha, 110, arqTxt);	//le a uma linha do arquivo base

        if(!feof(arqTxt)){

	    //cont++;
        //printf("Contador: %d\n",cont);

        regTemp = alocaDados();

        leTupla(linha,&regTemp);			//separa os campos

        //printf("CODIGO:%s NOME:%s Data:%s Local:%s \n",temp.CODIGO,temp.NOME,temp.DATA_NASC,temp.LOCAL);

        codigo = atoi(regTemp.CODIGO);
		resultHash = funcHash1(codigo);	//calcula a posicao do bucket no qual os dados serao gravados
		//printf("Hash Calculado pela h1: %d referente ao cod: %d\n",resultHash,codigo);
		//printf("NOME %s, Data: %s, Local: %s\n",regTemp.NOME,regTemp.DATA_NASC,regTemp.LOCAL);

        carregaDados(arqDados, &regTemp, resultHash);

        free(regTemp.CODIGO);
        free(regTemp.NOME);
        free(regTemp.DATA_NASC);
        free(regTemp.LOCAL);

		////Grava o bloco de dados na memoria secundaia na posicao encontrada
		//loadBloc(arqDados, arqIndices, reg, b, bi, key_hash);

         }
	}

    free(linha);	//desalocada memoria
	fclose(arqTxt);	//fecha arquivo TXT
	fclose(arqDados);	//fecha arquivo TXT

    printf("Ocorreram %d colisoes",contColisao);

	printf("\nCriacao do arquivo de dados concluida com sucesso! Pressione qualquer tecla para sair\n\n");
    getchar();


    return 0;
}
